(cl:in-package #:coalton-native-tests)

(named-readtables:in-readtable coalton:coalton)

;; tests for loops

(define-test experimental-loops-repeat-test ()
  (let ((x (cell:new 0)))
    (experimental:repeat (0)
      (cell:increment! x))
    (is (== 0 (cell:read x)))
    (experimental:repeat (100)
      (cell:increment! x))
    (is (== 100 (cell:read x)))))

(define-test experimental-loops-dotimes-test ()
  (let ((x (cell:new 0)))
    (experimental:dotimes (i 0)
      (cell:update! (+ i) x))
    (is (== 0 (cell:read x)))
    (experimental:dotimes (i 10)
      (cell:update! (+ i) x))
    (is (== 45 (cell:read x)))))

(define-test experimental-loops-everytimes-test ()
  (is (experimental:everytimes (i 0) False))
  (is (experimental:everytimes (i 0) True))
  (is (not (experimental:everytimes (i 1) False)))
  (is (experimental:everytimes (i 1) True))

  (is (experimental:everytimes (i 10) (< i 10)))
  (is (not (experimental:everytimes (i 11) (< i 10)))))

(define-test experimental-loops-sometimes-test ()
  (is (not (experimental:sometimes (i 0) False)))
  (is (not (experimental:sometimes (i 0) True)))
  (is (not (experimental:sometimes (i 1) False)))
  (is (experimental:sometimes (i 1) True))

  (is (not (experimental:sometimes (i 10) (>= i 10))))
  (is (experimental:sometimes (i 11) (>= i 10))))

(define-test experimental-loops-sumtimes-test ()
  (is (zero? (experimental:sumtimes (i 0) 10)))
  (is (== 100 (experimental:sumtimes (i 10) 10)))
  (is (== 45 (experimental:sumtimes (i 10) i))))

(define-test experimental-loops-prodtimes-test ()
  (is (== 1 (experimental:prodtimes (i 0) 10)))
  (is (== 100000 (experimental:prodtimes (i 5) 10)))
  (is (== (^ 2 10) (experimental:prodtimes (i 5) (^ 2 i)))))

(define-test experimental-loops-collecttimes-test ()
  (is (list:null? (experimental:collecttimes (i 0) i)))
  (is (== (make-list 0 1 4 9) (experimental:collecttimes (i 4) (* i i)))))

(define-test experimental-loops-besttimes-test ()
  (is (== 10 (experimental:besttimes (i 11 >) i)))
  (is (== 100 (experimental:besttimes (i 11 >) (* i i)))))

(define-test experimental-loops-argbesttimes-test ()
  (is (== 10 (experimental:argbesttimes (i 11 >) i)))
  (is (== 10 (experimental:argbesttimes (i 11 >) (* i i)))))

(define-test experimental-loops-dolist-test ()
  (let ((xs (make-list 0 1 2 3 4))
        (c (cell:new 0)))
    (experimental:dolist (x xs)
      (cell:update! (+ x) c))
    (is (== 10 (cell:read c)))))

(define-test experimental-loops-dolists-test ()
  (let ((xs (make-list 0 1 2 3 4 5 6))
        (ys (make-list 0 10 20 30 40))
        (c (cell:new 0)))
    (experimental:dolists ((x xs) (y ys))
      (cell:update! (+ (+ x y)) c))
    (is (== 110 (cell:read c)))))

(define-test experimental-loops-dolist-enumerated-test ()
  (let ((xs (make-list 0 1 4 9 16))
        (c (cell:new 0)))
    (experimental:dolist-enumerated (i x xs)
      (cell:update! (+ (+ i x)) c))
    (is (== 40 (cell:read c)))))

(define-test experimental-loops-dorange-test1 ()
  (let ((c (cell:new 0)))
    (experimental:dorange (x 0) (cell:increment! c))
    (is (zero? (cell:read c)))
    (experimental:dorange (x 5) (cell:update! (+ (* x x)) c))
    (is (== 30 (cell:read c)))))

(define-test experimental-loops-dorange-test2 ()
  (let ((c (cell:new Nil)))
    (experimental:dorange (x -2 2) (cell:push! c x))
    (is (== (make-list 1 0 -1 -2) (cell:read c)))
    (cell:write! c Nil)
    (experimental:dorange (x 2 -2) (cell:push! c x))
    (is (== (make-list -1 0 1 2) (cell:read c)))))

(define-test experimental-loops-dorange-test3 ()
  (let ((c (cell:new Nil)))
    (experimental:dorange (x -2 2 -2) (cell:push! c x))
    (experimental:dorange (x 2 -2 2) (cell:push! c x))
    (is (list:null? (cell:read c)))
    (experimental:dorange (x -2 2 2) (cell:push! c x))
    (experimental:dorange (x 6 2 -2) (cell:push! c x))
    (is (== (make-list 4 6 0 -2) (cell:read c)))))

(define-test experimental-loops-dorange-test4 ()
  (let ((c (cell:new Nil)))
    (let ((start -2) (stop 2) (step -2))
      (experimental:dorange (x start stop step)
        (cell:push! c x)))
    (let ((start 2) (stop -2) (step 2))
      (experimental:dorange (x start stop step)
        (cell:push! c x)))
    (is (list:null? (cell:read c)))
    (let ((start -2) (stop 2) (step 2))
      (experimental:dorange (x start stop step)
        (cell:push! c x)))
    (let ((start 6) (stop 2) (step -2))
      (experimental:dorange (x start stop step)
        (cell:push! c x)))
    (is (== (make-list 4 6 0 -2) (cell:read c)))))

